package lesson.ch5;

import java.util.ArrayDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Customer implements Runnable {
	MyBlockQ list;

	public Customer(MyBlockQ list) {
		this.list = list;
	}

	public void run() {
		while (true) {
			list.get();
			System.out.println(Thread.currentThread().getId() + " get a item");
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

public class MyBlockQ {
	public static Condition con;

	public static ReentrantLock lock;

	public static void main(String[] args) {
		MyBlockQ bq = new MyBlockQ(10);
		ExecutorService es1 = Executors.newFixedThreadPool(10);
		ExecutorService es2 = Executors.newFixedThreadPool(10);
		for (int i = 0; i < 10; i++) {
			es1.execute(new Productor(bq));
			es2.execute(new Customer(bq));
		}
		es1.shutdown();
		es2.shutdown();
	}

	ArrayDeque<Object> list;
	private int maxSize;
	private int size;

	private int total;

	public MyBlockQ() {
		lock = new ReentrantLock();
		con = lock.newCondition();
		size = 0;
		list = new ArrayDeque<Object>();
		total = 0;
	}

	public MyBlockQ(int maxsize) {
		this();
		this.maxSize = maxsize;
	}

	public Object get() {
		Object item = null;
		lock.lock();
		if (isEmpty()) {
			System.out.println("Is Empty");
			try {
				con.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		} else {
			item = list.getFirst();
			size--;
			con.signalAll();
		}
		lock.unlock();
		return item;

	}

	public int getMaxSize() {
		return maxSize;
	}

	public int getTotal() {
		return total;
	}

	public boolean isEmpty() {

		return size == 0;
	}

	public boolean isFull() {

		return size == maxSize;
	}

	public void put(Object item) {
		lock.lock();
		if (isFull()) {
			System.out.println("Is Full");
			try {
				con.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			list.addLast(item);
			size++;
			total++;
			con.signalAll();

		}
		lock.unlock();

	}

	public void setMaxSize(int max) {
		this.maxSize = max;
	}
}

class Productor implements Runnable {
	MyBlockQ list;

	public Productor(MyBlockQ list) {
		this.list = list;
	}

	public void run() {
		for (int i = 0; i < 100; i++) {
			list.put(new Object());
			System.out.println(Thread.currentThread().getId() + " prduct a item. total:" + list.getTotal());
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
